# -*- coding: utf-8 -*-


# cmap2owl -- Helper application to convert from concept maps to OWL ontologies
# Copyright (c) 2008-2013  Rodrigo Rizzi Starr
#  
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#  
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#  
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.


'''
Contains some simple inference rules about concepts

@author: Rodrigo Rizzi Starr
@copyright: Copyright © 2008-2013 Rodrigo Rizzi Starr
@license: MIT License
@contact: rodrigo.starr@gmail.com
'''


from infoProvider import SimpleInfoProvider, UnionOfInfoProviders
from mapperRule import MapperRule
from mapperQuestion import MapperQuestion
from multiQuestion import MultiQuestion
from log import log
log.debug('Loaded...')


class ConceptRule(MapperRule):
    '''Infers the existence of concepts and individuals'''

    def __init__(self, db):

        classifiers = ['enumerationPhrases',
                       'classificationPhrases',
                       'individualizationPhrases',
                       ]
          
        # Heuristics to identify a concept
        rules = [
                 'inferenceGroup(conceptRule, [ class(_), '
                    'individual(_) ])',

                 'class(Concept) :- '
                      'setof(R, (fromPartRelation(R, Concept); '
                                'toPartRelation(R, Concept)), Set), '
                     'length(Set, L), L > 0, concept(Concept)',
                     
                'individual(Concept) :- '
                   'setof(R, ('
                             '(individualizationRelation(R); '
                              'classificationRelation(R); '
                              'enumerationRelation(R)),'
                              '(fromPartRelation(R, Concept); '
                               'toPartRelation(R, Concept)) '
                             '), '
                         'Set), '
                    'length(Set, L), L > 0, concept(Concept)',

                 'classOWL(Concept) :- '
                    'isTrue(class(Concept))',
                 'individualOWL(Concept) :- '
                    'isTrue(individual(Concept))',
                   ]
          
        MapperRule.__init__(self, 'Concepts', db, rules, classifiers)
      
    def getClassQuestions(self):
        '''Returns a list of questions if a certain concept can be a class'''
        
        questions = []
        query = ('possible(class(Concept)), '
                 '\+ possible(individual(Concept))')
        
        classes = list(self.db.query(query))
        
        for answer in classes:
            answer['Ids'] = [answer['Concept']]
            questions.append(MapperQuestion(
                self.db,
                answer,
                'Is "<b>%(Concept)s</b>" a class?',
                'class(%(Concept)s)',
                 helpFile = 'conceptAndIndividual',
            ))
            
        return questions
      
    def getIndividualQuestions(self):
        '''Returns a list of questions if a certain concept can be an
           individual'''
        
        questions = []
        query = ('possible(individual(Concept)), '
                 '\+ possible(class(Concept))')
        
        individuals = list(self.db.query(query))
        
        for answer in individuals:
            answer['Ids'] = [answer['Concept']]
            questions.append(MapperQuestion(
                self.db,
                answer,
                'Is "<b>%(Concept)s</b>" an individual?',
                'individual(%(Concept)s)',
                 helpFile = 'conceptAndIndividual',
            ))
            
        return questions
      
    def getDoubleQuestions(self):
        '''Returns a list of questions for a concept that can be both a class or
           an individual.
        '''
        questions = []
        query = ('possible(class(Concept)), '
                 'possible(individual(Concept))')
                
        concepts = self.db.query(query)
        
        for answer in concepts:
            answer['Ids'] = [answer['Concept']]
            questions.append(MultiQuestion(
                    self.db,
                    answer,
                    'Is "<b>%(Concept)s</b>" representing a class or an'
                       'individual?',
                    {'Class': 'class(%(Concept)s)',
                     'Individual': 'individual(%(Concept)s)',},
                    helpFile = 'conceptAndIndividual',
                    noneCondition = 'isTrue(hasPart(Relation, Owner, PartSet)),'
                     '(Owner = %(Concept)s; member(%(Concept)s, PartSet))',
                    ))
              
        return questions
      
    def getQuestions(self):
        '''Questions about concepts'''
        questions = []
        questions.extend(self.getDoubleQuestions())
        questions.extend(self.getClassQuestions())
        questions.extend(self.getIndividualQuestions())

        return questions
  
    def getInfoProvider(self):
        '''Returns an info provider about classes and individuals'''
        
        classProvider = SimpleInfoProvider(self.db,
                                     'isTrue(class(%s))',
                                     'This element is a class')
        indProvider = SimpleInfoProvider(self.db,
                                     'isTrue(individual(%s))',
                                     'This element is an individual')
        
        return UnionOfInfoProviders(classProvider, indProvider)
        


